FUNCTION_BLOCK DCO_WriteDriveArray32b
TITLE = 'DCO_WriteDriveArray32b'

// This FB write a Array of 32 Bit parameters of a connected drive
// The implementation is independant of the used Bussystem
// 
// Versionshistory:
// 1.0 Ersterstellung E.Dittmann 
// 1.1 Timeout ED
// 2.0 Release
 
// USED S7 Systemfuctions:
// SFB52 RDREC
// SFB53 WRREC
// SFB4  TON

VERSION : '2.0'
AUTHOR  : 'Lenze'
FAMILY  : 'DCO'
NAME : 'WArray32' // ( 8 Zeichen max.) 
KNOW_HOW_PROTECT

VAR_INPUT
    iDiagnosticADR      : INT   := 2000;             // Diagnostic adress of the drive (Hardwareconfig S7)
    xExecute            : BOOL  := FALSE;            
    xUseIndexAsParam    : BOOL  := True;            // True = Lenze index number at wIndex
    iIndex              : INT   := 24058;           // Default = Codestelle 517
    iSubIndex           : INT   := 1;                
    iCountSubIndex      : INT   := 32;               // Number of Subcodevalues Max=32
    iType               : INT   := 7;               // 2=Int8, 3=Int16, 4=Int32, 5=Unsigned8, 6=Unsigned16, 7=Unsigned32, 65=Byte, 66=Word, 67=DWord
    iScalingFactor      : INT   := 1;               // Scaling factor from attributlist
    rData               : ARRAY[1..32]OF REAL   := 32(0.0);             // [32] Parametervalue as REAL
    
END_VAR

VAR_OUTPUT
    xDone               :BOOL   := False;
    xBusy               :BOOL   := False;
    xError              :BOOL   := False;
    xTimeout            :BOOL   := False;
    iDataType           :INT    := 0;               // 2=Int8, 3=Int16, 4=Int32, 5=Unsigned8, 6=Unsigned16, 7=Unsigned32, 65=Byte, 66=Word, 67=DWord
    dwErrorcode         :DWORD   := 0;              // If a error xError=True dwData = Errorcode
       
END_VAR

VAR
    xExecute_Old        : BOOL  :=False;
    xReadOld            : BOOL  :=False;
    xWriteReq           : BOOL;
    xReadReq            : BOOL  :=False;
    xStartDelay         : BOOL  :=False;
    wDiagnosticADR      : WORD;
    parWrite            : WRREC;
    xWriteDone          : BOOL;
    xWriteBusy          : BOOL;
    xWriteError         : BOOL;
    dwWriteStatus       : DWORD;
    scWriteRecord       : STRUCT
                            Request_Reference001    : BYTE := B#16#0;  
                            Request_ID_001          : BYTE := B#16#2;  
                            Axis001                 : BYTE := B#16#0;   
                            Number_Parameter001     : BYTE := B#16#1;  
                            Attribute001            : BYTE := B#16#10; 
                            Number_Subcodes001      : BYTE := B#16#0;  
                            Index001                : INT  := 24058;   
                            Subindex001             : INT  := 0;        
                            Format001               : BYTE := B#16#43; // Format: 2=Int8, 3=Int16, 4=Int32, 5=Unsigned8, 6=Unsigned16, 7=Unsigned32, 9=String, 10=OctString, 65=Byte, 66=Word, 67=DWord
                            Number_values001        : BYTE := B#16#1;  
                            dwData                  : ARRAY[1..32]OF DWORD   := 32(0);             // [32] Parametervalue as REAL
                          END_STRUCT;
    parRead             : RDREC;
    xReadValid          : BOOL;
    xReadBusy           : BOOL;
    xReadError          : BOOL;
    dwReadStatus        : DWORD;
    scReadRecord        : STRUCT
                            Request_Refernce011     : BYTE := B#16#0;   
                            Response_ID_011         : BYTE := B#16#0;   
                            Axis011                 : BYTE := B#16#0;   
                            Number_Paramater011     : BYTE := B#16#0;   
                            Format011               : BYTE := B#16#0;   // Format: 2=Int8, 3=Int16, 4=Int32, 5=Unsigned8, 6=Unsigned16, 7=Unsigned32, 9=String, 10=OctString, 65=Byte, 66=Word, 67=DWord
                            Number_Values011        : BYTE := B#16#0;   
                            Errorcode011            : DWORD:= 0;        
                          END_STRUCT;
    dwtest1             :DWORD;
    dwtest2             :DWORD;                    
    dwtest3             :DWORD;
    iCount1             :INT;
    iCount2             :INT; 
    delay               :TON;                
    timeout             :TON;
END_VAR

LABEL
    ENDE;
END_LABEL

// Timeout           
Timeout(IN := xExecute  AND NOT xDone        
          ,PT := T#10s                      
          ); 
//xError:= Timeout.q;
xTimeout:= Timeout.q;


IF NOT xExecute AND NOT xWriteReq AND NOT xReadReq THEN
    GOTO ENDE;
ELSIF NOT xExecute AND ( xWriteReq OR xReadReq )THEN // Reset mit laufendem Auftrag
    xWriteReq := False;
    xReadReq  := False;
END_IF;



wDiagnosticADR:=INT_TO_WORD(iDiagnosticADR);

IF (xExecute = true) AND (xExecute_Old = False) THEN
    xWriteReq := True;
    xExecute_Old := True;
    // Reset Datenbereich
    FOR iCount1 := 1 TO 32 BY 1 DO
        scWriteRecord.dwData[iCount1]:=0;
    END_FOR;
    scReadRecord.Response_ID_011:=0;
    scReadRecord.Format011:=0;
    scReadRecord.Number_Values011:=0;
    scReadRecord.Number_Paramater011:=0;
    scReadRecord.Errorcode011:=0;
    dwtest1:=0;
    dwtest2:=0;
    dwtest3:=0;
    xReadReq  := False;
    iDataType := 0;
    dwErrorcode :=0;
END_IF;

IF xUseIndexAsParam THEN
    scWriteRecord.Index001:= 24575 - iIndex;
ELSE
    scWriteRecord.Index001:= iIndex;
END_IF;

scWriteRecord.Subindex001:=iSubIndex;
scWriteRecord.Number_Subcodes001:= INT_TO_BYTE(iCountSubIndex);
scWriteRecord.Format001 := INT_TO_BYTE(iType);
FOR iCount2 := 1 TO BYTE_TO_INT(scWriteRecord.Number_Subcodes001) BY 1 DO
    scWriteRecord.dwData[iCount2]:=DINT_TO_DWORD(REAL_TO_DINT(rData[iCount2] * iScalingFactor));
END_FOR;


parWrite(REQ := xWriteReq                       // IN: BOOL
            ,ID := wDiagnosticADR 
            ,INDEX := 47                        // immer47
            ,LEN := 140                          // IN: INT
            ,RECORD := scWriteRecord            // INOUT: ANY
            ); 
   xWriteDone := parWrite.DONE;                 // OUT: BOOL
   xWriteBusy := parWrite.BUSY;                 // OUT: BOOL
   xWriteError:= parWrite.ERROR;                // OUT: BOOL
   dwWriteStatus:= parWrite.STATUS;             // OUT: DWORD

  
parRead(REQ := xReadReq                         // IN: BOOL
            ,ID := wDiagnosticADR               // IN: DWORD
            ,INDEX := 47                        // immer 47
            ,MLEN := 10                         // IN: INT 
            ,RECORD := scReadRecord             // INOUT: ANY
            ); 
   xReadValid:= parRead.VALID;                  // OUT: BOOL
   xReadBusy:= parRead.BUSY;                    // OUT: BOOL
   xReadError:= parRead.ERROR;                  // OUT: BOOL
   dwReadStatus:= parRead.STATUS;               // OUT: DWORD

xBusy := xWriteBusy OR xReadBusy;

// Verzögerung der Fehlermeldung aufgrund der Statusmeldung "Teilnehmer nicht bereit"
delay(IN :=  xWriteError OR  xReadError         // IN: BOOL
          ,PT := T#1s                           // IN: TIME
          ); 
 

IF  xWriteDone AND NOT xDone AND NOT xReadOld THEN
    xWriteReq := False;
    xReadReq  := True;
    xReadOld  := True;
    dwWriteStatus:= parWrite.STATUS; 
END_IF;


IF xWriteError AND delay.q THEN
    xError:=True;
    xWriteReq := False;
ELSIF  xReadError AND delay.q THEN
    xError:=True;
    xReadReq:=False;
    dwReadStatus:= parRead.STATUS;
END_IF;


IF xReadValid  THEN
    xReadReq:=False;
    iDataType:=BYTE_TO_INT(scReadRecord.Format011);
    xDone:=True;
    dwErrorcode:=scReadRecord.Errorcode011;
   
    IF ( scReadRecord.Response_ID_011 = 129 ) OR (iDataType = 68) THEN
        xError:=True;
        xReadReq:=False;
    END_IF;
END_IF;  

ENDE:
 
IF NOT xExecute THEN
    xExecute_Old:=False;
    xReadOld:=False;
    xError:=False;
    xBusy:=False;  
    xDone:=False;
    xWriteError:=False;
    xReadError:=False;
    xReadReq:=False;
    xWriteReq := False;

END_IF;

END_FUNCTION_BLOCK
